using System;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

using Planar.PT120.Properties;

namespace Planar.PT120
{
    public class MouseSimulator
    {
        #region Constructors
        private MouseSimulator() { }
        #endregion

        #region Win32 API values
        [DllImport("user32.dll")]
        private extern static void mouse_event(int dwFlags, int X, int Y, int Buttons, int dwExtraInfo);

        private const int MOUSEEVENTF_MOVE = 0x0001;
        private const int MOUSEEVENTF_LEFTDOWN = 0x0002;
        private const int MOUSEEVENTF_LEFTUP = 0x0004;
        private const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
        private const int MOUSEEVENTF_RIGHTUP = 0x0010;
        private const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        private const int MOUSEEVENTF_MIDDLEUP = 0x0040;
        private const int MOUSEEVENTF_ABSOLUTE = 0x8000; 
        #endregion

        #region Member fields and properties
        public static double CalibrationX
        {
            get 
            { 
                return Settings.Default.CalibrationX; 
            }
            set
            {
                Settings.Default.CalibrationX = value;
                Settings.Default.Save();
            }
        }
        public static double CalibrationY
        {
            get { return Settings.Default.CalibrationY; }
            set
            {
                Settings.Default.CalibrationY = value;
                Settings.Default.Save();
            }
        }
        #endregion

        #region Process Command
        private static volatile bool MouseDown = false;
        public static void ProcessCommand(Command cmd)
        {
            Point p = GetNormalized(cmd.X, cmd.Y);
            if (cmd.CommandType == CommandType.Touch)
            {
                mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
                    p.X, p.Y, 0, 0);

                //If the mouse is UP send a mousedown event also.
                //mouse up will be send when a Release command type comes.
                if (!MouseDown)
                {
                    mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE,
                        p.X, p.Y, 0, 0);
                    MouseDown = true;
                }
            }
            else if (cmd.CommandType == CommandType.Release)
            {
                mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
                    p.X, p.Y, 0, 0);
                mouse_event(MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE,
                    p.X, p.Y, 0, 0);
                MouseDown = false;
            }
        } 
        #endregion

        #region Helpers
        private static Point GetNormalized(int X, int Y)
        {
            Point p = new Point(X, Y);
            Screen s = Screen.FromPoint(p);

            double dx = (double)(X - CalibrationX) / 1000.0;
            double dy = (double)(Y + CalibrationY) / 1000.0;

            p.X = Convert.ToInt32((s.Bounds.Width * dx) * (65535 / s.Bounds.Width));

            p.Y = Convert.ToInt32((s.Bounds.Height - (s.Bounds.Height * dy)) * (65535 / s.Bounds.Height));

            return p;
        } 
        #endregion
    }
}
